﻿//-----------------------------------------------------------------------
// <copyright file="Types.cs">
//     Copyright (c) Nicole Calinoiu. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Diagnostics.CodeAnalysis;

using Microsoft.FxCop.Sdk;

namespace Bordecal.FxCop.Sdk
{
	/// <summary>
	/// Container for well-known <see cref="TypeNode"/> definitions.
	/// </summary>
	public static class Types
	{
		private static readonly object _lockIndicator = new object();

		private static TypeDefinitions Container { get; set; }

		/// <summary>
		/// Gets <see cref="TypeNode"/> for <see cref="CompilerGeneratedAttribute"/>.
		/// </summary>
		public static TypeNode CompilerGeneratedAttribute
		{
			get
			{
				return Types.GetType(c => c.CompilerGeneratedAttribute);
			}
		}

		/// <summary>
		/// Gets <see cref="TypeNode"/> for <see cref="NotImplementedException"/>.
		/// </summary>
		public static TypeNode NotImplementedException
		{
			get
			{
				return Types.GetType(c => c.NotImplementedException);
			}
		}

		/// <summary>
		/// Gets <see cref="TypeNode"/> for <see cref="ParamArrayAttribute"/>.
		/// </summary>
		[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Param",
			Justification = "Name matches target type name.")]
		public static TypeNode ParamArrayAttribute
		{
			get
			{
				return Types.GetType(c => c.ParamArrayAttribute);
			}
		}

		private static TypeNode GetType(Func<TypeDefinitions, TypeNode> selector)
		{
			Types.EnsureTypeDefinitions();
			return selector(Types.Container);
		}

		private static void EnsureTypeDefinitions()
		{
			if (Types.Container == null)
			{
				lock (Types._lockIndicator)
				{
					if (Types.Container == null)
					{
						Types.Container = new TypeDefinitions();
					}
				}
			}
		}

		[SuppressMessage("Microsoft.StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented",
			Justification = "False positive.")]
		private sealed class TypeDefinitions
		{
			internal TypeDefinitions()
			{
				this.CompilerGeneratedAttribute = TypeDefinitions.GetType(FrameworkAssemblies.Mscorlib, "System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
				this.NotImplementedException = TypeDefinitions.GetType(FrameworkAssemblies.Mscorlib, "System", "NotImplementedException");
				this.ParamArrayAttribute = TypeDefinitions.GetType(FrameworkAssemblies.Mscorlib, "System", "ParamArrayAttribute");
			}

			internal TypeNode CompilerGeneratedAttribute { get; private set; }

			internal TypeNode NotImplementedException { get; private set; }

			internal TypeNode ParamArrayAttribute { get; private set; }

			private static TypeNode GetType(AssemblyNode assembly, string namespaceName, string typeName)
			{
				return assembly.GetType(Identifier.For(namespaceName), Identifier.For(typeName));
			}
		}
	}
}